home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C ++ / Applications / FlyThrough 1.1.2 / src / Source / Vehicle Classes / CVehicleViewPane.cp < prev    next >
Encoding:
Text File  |  1997-03-17  |  13.2 KB  |  493 lines  |  [TEXT/CWIE]

  1. //
  2. //    CVehicleViewPane.cp
  3. //
  4. //    The view from the vehicle (a camera and lights) into a QD3D world.
  5. //
  6. //    By James Jennings
  7. //    Started July 9 1996
  8. //
  9.  
  10. #include "CVehicleViewPane.h"
  11. #include "CGetKeys.h"
  12. #include "CQTVRCursor.h"
  13. #include "CColorPicker.h"
  14.  
  15. const SDimension16    kDefaultSize = { 300, 200 };
  16. const TQ3Point3D    kZero = { 0, 0, 0 };
  17.  
  18. CVehicleViewPane * CVehicleViewPane::CreateFromStream( LStream *inStream )
  19. {
  20.     return new CVehicleViewPane( inStream );
  21. }
  22.  
  23. CVehicleViewPane::CVehicleViewPane( LStream *inStream )
  24.     : CQD3DPane( inStream ), mVehicle( this ), 
  25.         mCenter(kZero), mSceneRadius(0), mLastTime(0)
  26. {
  27.     // In case kDefaultSize is not the pane's real size.
  28.     AdjustQ3ViewToFrame();
  29.     
  30. //    SetCamera( mVehicle.GetCamera() );
  31. //    SetLights( mVehicle.GetLights() );
  32. }
  33.  
  34. void    CVehicleViewPane::SetModel( TQ3GroupObject inGroup )
  35. {
  36.     CQD3DPane::SetModel(inGroup);
  37.     
  38.     // Tell the vehicle the scale of the scene.
  39.     TQ3BoundingBox theBox;
  40.     CalcBoundingBox(theBox);
  41.     
  42.     TQ3Vector3D diagonal;
  43.     ::Q3Point3D_Subtract( &theBox.max, &theBox.min, &diagonal );
  44.     float scale = ::Q3Vector3D_Length(&diagonal);
  45.     
  46.     // Avoid problems with empty scenes.
  47.     if (scale <= kQ3RealZero) scale = 1;
  48.     
  49.     mVehicle.SetScale(scale);
  50.     
  51.     // Remember the center of the scene.
  52.     ::Q3Vector3D_Scale(&diagonal, 0.5, &diagonal);
  53.     ::Q3Point3D_Vector3D_Add(&theBox.min, &diagonal, &mCenter);
  54.     mSceneRadius = scale/2;
  55.     
  56.     StartIdling();    // so that the modifier keys can be read
  57. }
  58.  
  59. TQ3CameraObject    CVehicleViewPane::GetCamera(void)
  60. {
  61.     // We store the camera in the vehicle.
  62.     return mVehicle.GetCamera();
  63.     
  64.     // debug
  65. //    return CQD3DPane::GetCamera();
  66. }
  67.  
  68. void    CVehicleViewPane::SetCamera( TQ3CameraObject inCamera )
  69. {
  70.     // We store the camera in the vehicle.
  71.     mVehicle.SetCamera(inCamera);
  72.     RebuildView();    // forces the view to be rebuilt
  73. }
  74.  
  75. TQ3GroupObject    CVehicleViewPane::GetLights(void)
  76. {
  77.     if ( mLights == nil ) {
  78.         // No lights were supplied. Get the default lights from the vehicle.
  79.         
  80.         // make the headlight group
  81.         TQ3GroupPosition pos;
  82.         mLights = ::Q3LightGroup_New();
  83.         ThrowIfNil_(mLights);
  84.         
  85.         // ambient light (so that our built in models are never totally dark)
  86.         TQ3LightData    data;
  87.         
  88.         data.isOn = kQ3True;
  89.         ::Q3ColorRGB_Set(&(data.color), 1.0, 1.0, 1.0); // White Light
  90.         data.brightness = .2;
  91.         
  92.         TQ3LightObject amb = ::Q3AmbientLight_New(&data);
  93.         ThrowIfNil_(amb);
  94.         
  95.         pos = ::Q3Group_AddObject( mLights, amb );
  96.         Q3Forget( amb );
  97.         ThrowIf_(pos==0);
  98.         
  99.         // Add the vehicle headlights
  100.         mVehicle.AddHeadlightsToGroup(mLights);
  101.  
  102.         // add the "extra light": One ambient and one directional.
  103.         pos = ::Q3Group_AddObject( mLights, mExtraLight.Get() );
  104.         ThrowIf_(pos==0);
  105.         pos = ::Q3Group_AddObject( mLights, mExtraLight2.Get() );
  106.         ThrowIf_(pos==0);
  107.     }
  108.     
  109.     return mLights;
  110. }
  111.  
  112. void    CVehicleViewPane::SetLights( TQ3GroupObject inGroup )
  113. {
  114.     // Add the vehicle headlights
  115.     mVehicle.AddHeadlightsToGroup(inGroup);
  116.     
  117.     // add the "extra light": One ambient and one directional.
  118.     TQ3GroupPosition pos;
  119.     pos = ::Q3Group_AddObject( inGroup, mExtraLight.Get() );
  120.     ThrowIf_(pos==0);
  121.     pos = ::Q3Group_AddObject( inGroup, mExtraLight2.Get() );
  122.     ThrowIf_(pos==0);
  123.     
  124.     // pass on to superclass
  125.     CQD3DPane::SetLights(inGroup);
  126. }
  127.  
  128. void     CVehicleViewPane::ClickSelf(const SMouseDownEvent    &inMouseDown)
  129. {
  130.     // Use the mouse to change direction.
  131.     FocusDraw();    // need the correct port to do mouse calculations
  132.     
  133.     Point first = inMouseDown.whereLocal;
  134.     
  135.     // aLittle is the amount to yaw or pitch by, in radians/tick
  136.     const float aLittle    = Q3Math_DegreesToRadians( 0.05 );
  137.     const Int16 kMin = 2;    // minimum detectable mouse motion
  138.     const Int16 kMax = 72;    // maximum effective mouse motion
  139.     
  140.     long t0 = ::TickCount();
  141.     
  142.     while ( StillDown() ) {
  143.         
  144.         // don't do anything until some measurable time has passed.
  145.         float t1 = ::TickCount();
  146.         if (t0 == t1) continue;
  147.         
  148.         // Limit the apparent number of ticks between iterations
  149.         // so things don't get too difficult when the machine can't keep up.
  150.         Int32 t = t1 - t0;
  151.         if (t > 6) t = 6;
  152.         
  153.         // allow accelerations while dragging
  154.         Boolean needsToDraw = CheckAccelerationKeys( false );
  155.         
  156.         Point delta;
  157.         ::GetMouse( &delta );
  158.         ::SubPt( first, &delta );
  159.         
  160.         // Limit the maximum drag.
  161.         if (delta.h > kMax) delta.h = kMax;
  162.         else if (delta.h < -kMax) delta.h = -kMax;
  163.         if (delta.v > kMax) delta.v = kMax;
  164.         else if (delta.v < -kMax) delta.v = -kMax;
  165.         // Eliminate the kMin "dead" space
  166.         if (delta.h > kMin) delta.h -= kMin;
  167.         else if (delta.h < -kMin) delta.h += kMin;
  168.         else delta.h = 0;
  169.         if (delta.v > kMin) delta.v -= kMin;
  170.         else if (delta.v < -kMin) delta.v += kMin;
  171.         else delta.v = 0;
  172.         
  173.         if ( delta.h != 0 || delta.v != 0 ) {
  174.             
  175.             // how much to yaw and pitch by, scaled by time
  176.             float y = - aLittle * delta.h * t;
  177.             float p = - aLittle * delta.v * t;
  178.             
  179.             if ( y != 0 ) {
  180.                 mVehicle.YawBy( y );
  181.                 needsToDraw = true;
  182.             }
  183.             if ( p != 0 ) {
  184.                 mVehicle.PitchBy( p );
  185.                 needsToDraw = true;
  186.             }
  187.             
  188.             if (mVehicle.StabilizeRoll()) {
  189.                 needsToDraw = true;
  190.             }
  191.             
  192.             // adjust the cursor
  193.             #if 1
  194.             if ( y!=0 || p!=0 ) {
  195.                 float k = fabs(p);
  196.                 if ( fabs(y) > k ) k = fabs(y);
  197.                 
  198.                 CQTVRCursor::Set( - y * 256 / k, - p * 256 / k );
  199.             }
  200.             #else
  201.             // This version has trouble seeing non-diagonal cursors for small drags.
  202.             if ( delta.h!=0 || delta.v!=0 ) {
  203.                 CQTVRCursor::Set( delta.h, delta.v );
  204.             }
  205.             #endif
  206.             
  207.         } else {
  208.             CQTVRCursor::StopTracking();
  209.         }
  210.         
  211.         if ( needsToDraw )
  212.             Draw(nil);
  213.             
  214.         t0 = t1;
  215.         
  216.     }
  217.     
  218. }
  219.  
  220. void    CVehicleViewPane::SpendTime( const EventRecord &/*inMacEvent*/ )
  221. {
  222.     if ( CheckAccelerationKeys( true ) )
  223.         Draw(nil);
  224. }
  225.  
  226. void CVehicleViewPane::AdjustCursorSelf( 
  227.         Point /* inPortPt */, const EventRecord& /* inMacEvent */)
  228. {
  229.     CQTVRCursor::NotTracking();
  230. }
  231.  
  232. Boolean    CVehicleViewPane::CheckAccelerationKeys( Boolean inDraw )
  233. {    // Check the acceleration keys and move accordingly.
  234.     // Return 'true' if we moved.
  235.     
  236.     Boolean moved = false;    // the result
  237.     
  238.     if ( !IsTarget() )    // don't read the keys unless we're the target
  239.         return moved;
  240.     
  241.     // don't do anything unless a measurable time has passed
  242.     Int32 t1 = ::TickCount();
  243.     if ( mLastTime == t1 ) return false;
  244.     
  245.     float t = (float)(t1 - mLastTime);
  246.     
  247.     // Note: Reading inMacEvent.modifiers isn't reliable!
  248.     CGetKeys key;
  249.     Boolean shift   = key.IsDown(code_Shift);
  250.     Boolean fwd        = key.IsDown(code_Option)        && !shift;
  251.     Boolean back    = key.IsDown(code_Control)        && !shift;
  252.     Boolean left    = key.IsDown(code_LeftArrow)     && !shift;
  253.     Boolean right    = key.IsDown(code_RightArrow)     && !shift;
  254.     Boolean up        = key.IsDown(code_UpArrow)        && !shift;
  255.     Boolean down    = key.IsDown(code_DownArrow)     && !shift;
  256.     Boolean yawLt    = key.IsDown(code_LeftArrow)     &&  shift;
  257.     Boolean yawRt    = key.IsDown(code_RightArrow)     &&  shift;
  258.     Boolean pitchUp    = key.IsDown(code_UpArrow)        &&  shift;
  259.     Boolean pitchDn    = key.IsDown(code_DownArrow)    &&  shift;
  260.     Boolean rollRt    = key.IsDown(code_Option)        &&  shift;
  261.     Boolean rollLt    = key.IsDown(code_Control)        &&  shift;
  262.     
  263.     {
  264.         Int16 signX = ((right)?(1):(0)) - ((left)?(1):(0));
  265.         Int16 signY = ((fwd  )?(1):(0)) - ((back)?(1):(0));
  266.         Int16 signZ = ((up   )?(1):(0)) - ((down)?(1):(0));
  267.         
  268.         if ( mVehicle.Boost(t, signX, signY, signZ) )
  269.             moved = true;
  270.     }
  271.     
  272.     {
  273.         Int16 signY = ((yawLt  )?(1):(0)) - ((yawRt  )?(1):(0));
  274.         Int16 signP = ((pitchUp)?(1):(0)) - ((pitchDn)?(1):(0));
  275.         Int16 signR = ((rollRt )?(1):(0)) - ((rollLt )?(1):(0));
  276.         
  277.         if ( mVehicle.Spin(t, signY, signP, signR) )
  278.             moved = true;
  279.     }
  280.     
  281.     mLastTime = t1;
  282.     
  283.     return moved;
  284. }
  285.  
  286.  
  287. #pragma mark === Commander Methods ===
  288.  
  289. Boolean CVehicleViewPane::ObeyCommand(
  290.     CommandT    inCommand,
  291.     void        *ioParam)
  292. {
  293.     TQ3Status theStatus;
  294.     Boolean    cmdHandled = false;
  295.     
  296.     TQ3CameraPlacement place;
  297.     
  298.     switch ( inCommand ) {
  299.     
  300.     case cmd_LightsOff:
  301.     case cmd_LeftLight:
  302.     case cmd_RightLight:
  303.     case cmd_BothLights:
  304.     case cmd_CenteredLights:
  305.     case cmd_SeparatedLights:
  306.         mVehicle.SetLightMode(inCommand);
  307.         Draw(nil);
  308.         break;
  309.         
  310.     case cmd_ExtraLights:
  311.         Boolean isOn = mExtraLight.IsOn();
  312.         mExtraLight.TurnOn(!isOn);
  313.         mExtraLight2.TurnOn(!isOn);
  314.         Draw(nil);
  315.         break;
  316.         
  317.     case cmd_ViewFromFront:    // place on +Z axis
  318.         ::Q3Point3D_Set(&place.cameraLocation, mCenter.x, mCenter.y, mCenter.z + mSceneRadius*2);
  319.         ::Q3Point3D_Set(&place.pointOfInterest, mCenter.x, mCenter.y, mCenter.z);
  320.         ::Q3Vector3D_Set(&place.upVector, 0, 1, 0);
  321.         mVehicle.SetPlacement(place);
  322.         Refresh();
  323.         break;
  324.     case cmd_ViewFromBack:    // place on -Z axis
  325.         ::Q3Point3D_Set(&place.cameraLocation, mCenter.x, mCenter.y, mCenter.z - mSceneRadius*2);
  326.         ::Q3Point3D_Set(&place.pointOfInterest, mCenter.x, mCenter.y, mCenter.z);
  327.         ::Q3Vector3D_Set(&place.upVector, 0, 1, 0);
  328.         mVehicle.SetPlacement(place);
  329.         Refresh();
  330.         break;
  331.     case cmd_ViewFromLeft:    // place on -X axis (audience, not stage, left)
  332.         ::Q3Point3D_Set(&place.cameraLocation, mCenter.x - mSceneRadius*2, mCenter.y, mCenter.z);
  333.         ::Q3Point3D_Set(&place.pointOfInterest, mCenter.x, mCenter.y, mCenter.z);
  334.         ::Q3Vector3D_Set(&place.upVector, 0, 1, 0);
  335.         mVehicle.SetPlacement(place);
  336.         Refresh();
  337.         break;
  338.     case cmd_ViewFromRight:    // place on +X axis
  339.         ::Q3Point3D_Set(&place.cameraLocation, mCenter.x + mSceneRadius*2, mCenter.y, mCenter.z);
  340.         ::Q3Point3D_Set(&place.pointOfInterest, mCenter.x, mCenter.y, mCenter.z);
  341.         ::Q3Vector3D_Set(&place.upVector, 0, 1, 0);
  342.         mVehicle.SetPlacement(place);
  343.         Refresh();
  344.         break;
  345.     case cmd_ViewFromTop:    // place on +Y axis
  346.         ::Q3Point3D_Set(&place.cameraLocation, mCenter.x, mCenter.y + mSceneRadius*2, mCenter.z);
  347.         ::Q3Point3D_Set(&place.pointOfInterest, mCenter.x, mCenter.y, mCenter.z);
  348.         ::Q3Vector3D_Set(&place.upVector, 0, 0, -1);
  349.         mVehicle.SetPlacement(place);
  350.         Refresh();
  351.         break;
  352.     case cmd_ViewFromBottom:    // place on -Y axis
  353.         ::Q3Point3D_Set(&place.cameraLocation, mCenter.x, mCenter.y - mSceneRadius*2, mCenter.z);
  354.         ::Q3Point3D_Set(&place.pointOfInterest, mCenter.x, mCenter.y, mCenter.z);
  355.         ::Q3Vector3D_Set(&place.upVector, 0, 0, 1);
  356.         mVehicle.SetPlacement(place);
  357.         Refresh();
  358.         break;
  359.     case cmd_ViewFromCenter:    // place at mCenter, looking along Z axis
  360.         ::Q3Point3D_Set(&place.cameraLocation, mCenter.x, mCenter.y, mCenter.z);
  361.         ::Q3Point3D_Set(&place.pointOfInterest, mCenter.x, mCenter.y, mCenter.z + mSceneRadius*2);
  362.         ::Q3Vector3D_Set(&place.upVector, 0, 1, 0);
  363.         mVehicle.SetPlacement(place);
  364.         Refresh();
  365.         break;
  366.         
  367.     case cmd_LookAtCenter:    // disable if we are at the center?
  368.         mVehicle.GetPlacement(place);
  369.         // sanity check: Should never fail if we get FindCommandStatus() working.
  370.         float d = ::Q3Point3D_Distance( &place.cameraLocation, &mCenter );
  371.         if ( d < mSceneRadius/1000 ) break;
  372.         
  373.         ::Q3Point3D_Set(&place.pointOfInterest, mCenter.x, mCenter.y, mCenter.z);
  374.         mVehicle.SetPlacement(place);
  375.         Refresh();
  376.         break;
  377.             
  378.     case cmd_StabilizeRoll:
  379.         mVehicle.SetRollStabilized(!mVehicle.RollIsStabilized());
  380.         break;
  381.         
  382.     case cmd_BackgroundColor:
  383.         DoBackgroundColor();
  384.         break;
  385.         
  386.     default:
  387.         cmdHandled = LCommander::ObeyCommand( inCommand, ioParam );
  388.         break;
  389.     }
  390.     return cmdHandled;
  391. }
  392.  
  393. void CVehicleViewPane::FindCommandStatus(
  394.     CommandT    inCommand,
  395.     Boolean        &outEnabled,
  396.     Boolean        &outUsesMark,
  397.     Char16        &outMark,
  398.     Str255        outName)
  399. {
  400.     switch ( inCommand ) {
  401.     
  402.     // LDocument turns these on by default. I'll turn them off.
  403.     case cmd_Save:
  404.     case cmd_SaveAs:
  405.         outEnabled = false;
  406.         break;
  407.     
  408.     case cmd_LightsOff:
  409.     case cmd_LeftLight:
  410.     case cmd_RightLight:
  411.     case cmd_BothLights:
  412.         outEnabled = true;
  413.         outUsesMark = true;
  414.         outMark = ((inCommand == mVehicle.GetHeadlightState()) ? (checkMark) : (noMark));
  415.         break;
  416.     case cmd_CenteredLights:
  417.         outEnabled = true;
  418.         outUsesMark = true;
  419.         outMark = ((mVehicle.AreHeadlightsMerged()) ? (checkMark) : (noMark));
  420.         break;
  421.     case cmd_SeparatedLights:
  422.         outEnabled = true;
  423.         outUsesMark = true;
  424.         outMark = ((!mVehicle.AreHeadlightsMerged()) ? (checkMark) : (noMark));
  425.         break;
  426.     case cmd_ExtraLights:
  427.         outEnabled = true;
  428.         outUsesMark = true;
  429.         outMark = ((mExtraLight.IsOn()) ? (checkMark) : (noMark));
  430.         break;
  431.     case cmd_ViewFromFront:
  432.     case cmd_ViewFromBack:
  433.     case cmd_ViewFromLeft:
  434.     case cmd_ViewFromRight:
  435.     case cmd_ViewFromTop:
  436.     case cmd_ViewFromBottom:
  437.     case cmd_ViewFromCenter:
  438.         outEnabled = true;
  439.         break;
  440.         
  441.     case cmd_LookAtCenter:    // disable if we are at the center
  442.     #if 0
  443.         // This doesn't get called often enough to be useable.
  444.         // Do we take the overhead of calling SetUpdateCommandStatus()
  445.         // while rendering?
  446.         TQ3CameraPlacement place;
  447.         mVehicle.GetPlacement(place);
  448.         float d = ::Q3Point3D_Distance( &place.cameraLocation, &mCenter );
  449.         outEnabled = ( d > mSceneRadius/1000 );
  450.     #else
  451.         outEnabled = true;
  452.     #endif
  453.         break;
  454.             
  455.     case cmd_StabilizeRoll:
  456.         outEnabled = true;
  457.         outUsesMark = true;
  458.         outMark = ((mVehicle.RollIsStabilized()) ? (checkMark) : (noMark));
  459.         break;
  460.     
  461.     case cmd_BackgroundColor:
  462.         outEnabled = CColorPicker::IsAvailable();
  463.         break;
  464.         
  465.     default:
  466.         LCommander::FindCommandStatus(inCommand, outEnabled, outUsesMark, outMark, outName);
  467.     }
  468. }
  469.  
  470. void CVehicleViewPane::DoBackgroundColor()
  471. {
  472.     // Use the Color Picker to choose a new Clear Image Color.
  473.     TQ3ColorARGB theQ3Color;
  474.     GetClearImageColor(theQ3Color);
  475.     
  476.     RGBColor theQDColor;
  477.     theQDColor.red   = theQ3Color.r * 0xFFFF;
  478.     theQDColor.green = theQ3Color.g * 0xFFFF;
  479.     theQDColor.blue     = theQ3Color.b * 0xFFFF;
  480.     
  481.     CColorPicker picker;
  482.     if (picker.Choose(theQDColor)) {
  483.     
  484.         theQ3Color.r = (float)theQDColor.red / 0xFFFF;
  485.         theQ3Color.g = (float)theQDColor.green / 0xFFFF;
  486.         theQ3Color.b = (float)theQDColor.blue / 0xFFFF;
  487.         SetClearImageColor(theQ3Color);
  488.         
  489.         Refresh();
  490.     }
  491.     
  492. }
  493.